/*
 Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
 Original sources are available at www.latestbit.com

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 StdDataTypesCoder.hpp. Created on: 10.06.2009 12:05:24
 */

#ifndef STDDATATYPESCODER_HPP_
#define STDDATATYPESCODER_HPP_

#include "IDataTypesCoder.hpp"
#include "smartobjects/exceptions/DataTypesCoderException.hpp"

namespace smartobjects {

class StdDataTypesCoder : public IDataTypesCoder {
public:
	SO_DLLPRFX StdDataTypesCoder();
	SO_DLLPRFX virtual ~StdDataTypesCoder();

	SO_DLLPRFX virtual const std::string& getAlgorithm() const;

	SO_DLLPRFX virtual void encodeByte(const char value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual char decodeByte(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUByte(const unsigned char value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned char decodeUByte(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt16(const short value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual short decodeInt16(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUInt16(const unsigned short value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned short decodeUInt16(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt32(const int value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual int decodeInt32(ByteBuffer* buffer);
	SO_DLLPRFX virtual void encodeUInt32(const unsigned int value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeUInt32(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt64(const boost::int64_t value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual boost::int64_t decodeInt64(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUInt64(const boost::uint64_t value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual boost::uint64_t decodeUInt64(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeFloat(const float value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual float decodeFloat(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeDouble(const double value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual double decodeDouble(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeBigInteger(const BigInteger& value, ByteBuffer* buffer);
	SO_DLLPRFX virtual void decodeBigInteger(BigInteger& toValue, ByteBuffer* buffer);
	SO_DLLPRFX virtual void encodeBigDecimal(const BigDecimal& value, ByteBuffer* buffer);
	SO_DLLPRFX virtual void decodeBigDecimal(BigDecimal& toValue, ByteBuffer* buffer);

	SO_DLLPRFX virtual void encodeString(const std::string& value, ByteBuffer* buffer, bool bEmptyAsNull=false) ;
	SO_DLLPRFX virtual void decodeString(std::string& toString, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeWString(const std::wstring& value, ByteBuffer* buffer, bool bEmptyAsNull=false) ;
	SO_DLLPRFX virtual void decodeWString(std::wstring& toString, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeChar(const char value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual char decodeChar(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeWChar(const wchar_t value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual wchar_t decodeWChar(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeBoolean(const bool value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual bool decodeBoolean(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeDateTime(const time_t value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual time_t decodeDateTime(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeByteArray(const std::vector<char>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeByteArray(std::vector<char>& toValue, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUByteArray(const std::vector<unsigned char>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeUByteArray(std::vector<unsigned char>& toValue, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt16Array(const std::vector<short>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeInt16Array(std::vector<short>& toValue, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUInt16Array(const std::vector<unsigned short>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeUInt16Array(std::vector<unsigned short>& toValue, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt32Array(const std::vector<int>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeInt32Array(std::vector<int>& toValue, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUInt32Array(const std::vector<unsigned int>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeUInt32Array(std::vector<unsigned int>& toValue, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeInt64Array(const std::vector<boost::int64_t>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeInt64Array(std::vector<boost::int64_t>& toValue, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeUInt64Array(const std::vector<boost::uint64_t>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeUInt64Array(std::vector<boost::uint64_t>& toValue, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeFloatArray(const std::vector<float>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeFloatArray(std::vector<float>& toValue, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeDoubleArray(const std::vector<double>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeDoubleArray(std::vector<double>& toValue, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeBigIntegerArray(const std::vector<BigInteger>& fromArray, ByteBuffer* buffer);
	SO_DLLPRFX virtual void decodeBigIntegerArray(std::vector<BigInteger>& toArray, ByteBuffer* buffer );
	SO_DLLPRFX virtual void encodeBigDecimalArray(const std::vector<BigDecimal>& fromArray, ByteBuffer* buffer);
	SO_DLLPRFX virtual void decodeBigDecimalArray(std::vector<BigDecimal>& toArray, ByteBuffer* buffer );

	SO_DLLPRFX virtual void encodeStringArray(const std::vector<std::string>& fromArray, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeStringArray(std::vector<std::string>& toArray, ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual void encodeWStringArray(const std::vector<std::wstring>& fromArray, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeWStringArray(std::vector<std::wstring>& toArray, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeCharArray(const std::vector<char>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeCharArray(std::vector<char>& value, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeWCharArray(const std::vector<wchar_t>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeWCharArray(std::vector<wchar_t>& value, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeBooleanArray(const std::vector<bool>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeBooleanArray(std::vector<bool>& value, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeDateTimeArray(const std::vector<time_t>& value, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeDateTimeArray(std::vector<time_t>& value, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeObjectArray(const unsigned int arraySize, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeObjectArray( ByteBuffer* buffer ) ;

	SO_DLLPRFX virtual unsigned int encodeObjectListBegin( ByteBuffer* buffer );
	SO_DLLPRFX virtual unsigned int decodeObjectListBegin(ByteBuffer* buffer);

	SO_DLLPRFX virtual void encodeObjectListEnd(unsigned int nBeginPos, unsigned int nCount, ByteBuffer* buffer );
	SO_DLLPRFX virtual void decodeObjectListEnd(ByteBuffer* buffer);

	SO_DLLPRFX virtual void encodeObjectMap(const unsigned int mapSize, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeObjectMap(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeFloatingLength(const unsigned int len, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeFloatingLength(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeFixedLength(const unsigned int len, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeFixedLength(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeNull(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual bool decodeNull(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeStructureDataTypeBegin(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual bool decodeStructureDataTypeBegin(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeStructureDataTypeEnd(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeStructureDataTypeEnd(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual unsigned int encodeNamedDataPartBegin ( const std::string& structurePartName, ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual unsigned int decodeNamedDataPartBegin ( const std::string& structurePartName, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeNamedDataPartEnd ( const unsigned int beginPos, ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual void decodeNamedDataPartEnd ( const unsigned int beginPos, ByteBuffer* buffer ) ;

	SO_DLLPRFX virtual void encodeEnumDataType(const int selectedIndex, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual int decodeEnumDataType(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeExceptionDataTypeBegin(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual bool decodeExceptionDataTypeBegin(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeExceptionDataTypeEnd(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeExceptionDataTypeEnd(ByteBuffer* buffer) ;

	SO_DLLPRFX virtual unsigned int encodeEncryptedDataTypeBegin( ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual unsigned int decodeEncryptedDataTypeBegin( ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual void encodeEncryptedDataTypeEnd( const unsigned int beginPos, ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual void decodeEncryptedDataTypeEnd( ByteBuffer* buffer ) ;

	SO_DLLPRFX virtual void encodeObjectType ( const std::string& className, ByteBuffer* buffer ) ;
	SO_DLLPRFX virtual void decodeObjectType(std::string& className, ByteBuffer* buffer ) ;

	SO_DLLPRFX virtual unsigned int encodeChoiceDataTypeBegin(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual unsigned int decodeChoiceDataTypeBegin(ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeChoiceSelectedField(const std::string& selectedField, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeChoiceSelectedField(std::string& selectedField, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void encodeChoiceDataTypeEnd(const unsigned int beginPos, ByteBuffer* buffer) ;
	SO_DLLPRFX virtual void decodeChoiceDataTypeEnd(const unsigned int beginPos, ByteBuffer* buffer) ;

	SO_DLLPRFX virtual void encodeGrammar(ByteBuffer* buffer);
	SO_DLLPRFX virtual void decodeGrammar(ByteBuffer* buffer);

	SO_DLLPRFX virtual void reset();


public:
	enum DataTypeTags {
        NULL_TAG								 = 0,
        BOOLEAN_TAG                              = 1,
        BYTE_TAG                                 = 2,
        UBYTE_TAG                                = 3,
        INT16_TAG                                = 4,
        UINT16_TAG                               = 5,
        INT32_TAG                                = 6,
        UINT32_TAG                               = 7,
        INT64_TAG                                = 8,
        UINT64_TAG                               = 9,
        FLOAT_TAG                                = 10,
        DOUBLE_TAG                               = 11,
        STRING_TAG                               = 12,
        WSTRING_TAG                              = 13,
        CHAR_TAG                                 = 14,
        WCHAR_TAG                                = 15,
        DATETIME_TAG                             = 16,
        BIGINTEGER_TAG                           = 17,
        BIGDECIMAL_TAG                           = 18,
        BYTE_ARRAY_TAG                           = 50,
        UBYTE_ARRAY_TAG                          = 51,
        INT16_ARRAY_TAG                          = 52,
        UINT16_ARRAY_TAG                 		 = 53,
        INT32_ARRAY_TAG                          = 54,
        UINT32_ARRAY_TAG                 		 = 55,
        INT64_ARRAY_TAG                          = 56,
        UINT64_ARRAY_TAG                 		 = 57,
        FLOAT_ARRAY_TAG                          = 58,
        DOUBLE_ARRAY_TAG                 		 = 59,
        STRING_ARRAY_TAG                 		 = 60,
        WSTRING_ARRAY_TAG                		 = 61,
        CHAR_ARRAY_TAG                           = 62,
        WCHAR_ARRAY_TAG                          = 63,
        BOOLEAN_ARRAY_TAG                		 = 64,
        DATETIME_ARRAY_TAG               		 = 65,
		BIGINTEGER_ARRAY_TAG                     = 66,
		BIGDECIMAL_ARRAY_TAG                     = 67,
        OBJECT_ARRAY_TAG                 		 = 101,
        OBJECT_LIST_TAG            		 		 = 102,
        OBJECT_MAP_TAG                           = 103,

        OBJECT_TYPE_TAG                          = 0xEC,
        ENCRYPTED_DATA_TAG               		 = 0xED,
        NAMED_DATA_PART_TAG              		 = 0xEE,

        STRUCTURE_TYPE_BEGIN_TAG 				 = 0xF0,
        STRUCTURE_TYPE_END_TAG           		 = 0xF1,

        EXCEPTION_TYPE_BEGIN_TAG 				 = 0xF5,
        EXCEPTION_TYPE_END_TAG           		 = 0xF6,

        CHOICE_TYPE_TAG                          = 0xFA,
        ENUM_TYPE_TAG                            = 0xFC
	};

	enum UnicodeEncodingTypes {
		UCS_2									= 0x01
	};

protected:
	SO_DLLPRFX bool checkTag(ByteBuffer* buffer, DataTypeTags type, bool cannotBeNull=false);
	SO_DLLPRFX void encodeTag(DataTypeTags tag, ByteBuffer* buffer);
	SO_DLLPRFX unsigned char decodeTag(ByteBuffer* buffer);

	SO_DLLPRFX void encodeStringValue (const std::string& value, ByteBuffer* buffer) ;
	SO_DLLPRFX void decodeStringValue (std::string& toString, ByteBuffer* buffer) ;
	SO_DLLPRFX void encodeWStringValue (const std::wstring& value, ByteBuffer* buffer) ;
	SO_DLLPRFX void decodeWStringValue (std::wstring& toString, ByteBuffer* buffer) ;


	template < typename PT >
	inline void encodeNumberType( const PT value, DataTypeTags typeTag, ByteBuffer* buffer ) {
		encodeTag ( typeTag, buffer );
		PT valueToEncode = OSEndianTools::host_to_network(value);
		buffer->append( (unsigned char*)&valueToEncode, sizeof(PT) );
	}

	template < typename PT >
	inline PT decodeNumberType( DataTypeTags typeTag, ByteBuffer* buffer ) {
		checkTag(buffer, typeTag, true);
		PT* valueToDecode = (PT*) buffer->getDataAtPos();
		buffer->seek(sizeof(PT));
		return OSEndianTools::network_to_host( *valueToDecode );
	}

	template < typename PT >
	inline void encodeArrayOfNumbersType( const std::vector<PT>& value, DataTypeTags typeTag, ByteBuffer* buffer ) {
		encodeTag ( typeTag, buffer );
		encodeFloatingLength( value.size(), buffer );
		for(typename std::vector<PT>::const_iterator it = value.begin() ; it!= value.end(); it++) {
			PT valueToEncode = OSEndianTools::host_to_network( *it );
			buffer->append( (unsigned char*)&valueToEncode, sizeof(PT) );
		}
	}

	template < typename PT >
	inline void decodeArrayOfNumbersType( std::vector<PT>& value, DataTypeTags typeTag, ByteBuffer* buffer ) {
		value.clear();
		if( checkTag(buffer, typeTag ) ) {
			unsigned int nLen = decodeFloatingLength( buffer );
			if(nLen > buffer->getLenFromPos())
				throw DataTypesCoderException( boost::format( "Data length is out of bounds packet: %1% > %2%.")
					%nLen %buffer->getLenFromPos()
				);

			for(unsigned int i=0; i<nLen; i++) {
				PT* valueToDecode = (PT*) buffer->getDataAtPos();
				buffer->seek(sizeof(PT));
				value.push_back ( OSEndianTools::network_to_host( *valueToDecode ) );
			}
		}
	}

protected:
	class StdDataTypesCoderGrammar* m_poGrammar;
};

}

#endif /* STDDATATYPESCODER_HPP_ */
